/** Copyright (c) 2020 by XMX
 *	file : util.c -- some business logic functions
 *	since : 2020-08-23
 */

#include"tyger.h"

void doit (int fd)
{
	int is_static;
	struct stat sbuf;
	char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
	char filename[MAXLINE], cgiargs[MAXLINE];
	rio_t rio;
	
	/* Read request line and headers */
	Rio_readinitb(&rio, fd);
	if (!Rio_readlineb(&rio, buf, MAXLINE))
		return ;
	printf("%s", buf);
	sscanf(buf, "%s %s %s", method, uri, version);
//	printf("***test***request line: %s %s %s", method, uri, version);
	if (strcasecmp(method, "GET")) {
		clienterror(fd, method, "501", "Not Implemented",
					"Tyger does not implement this method");
		return ;
	}
	read_requesthdrs(&rio);

	/* Parse URI from GET request */
	is_static = parse_uri(uri, filename, cgiargs);
	if (stat(filename, &sbuf) < 0) {
		clienterror(fd, filename, "404", "Not Found",
					"Tyger couldn't find this file");
		return ;
	}

	if (is_static) {	/* Serve static content */
		if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
			clienterror(fd, filename, "403", "Forbidden",
						"Tyger couldn't read the file");
			return ;
		}
		serve_static(fd, filename, sbuf.st_size);
	} else {			/* Serve dynamic content */
		if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
			clienterror(fd, filename, "403", "Forbidden", 
						"Tyger couldn't run the CGI program");
			return ;
		}
		serve_dynamic(fd, filename, cgiargs);
	}
}

/* read and ignore the request header */
void read_requesthdrs (rio_t *rp)
{
	char buf[MAXLINE];
	printf("$start-->read_requestheaders-----------------------------\n");
	do {
		Rio_readlineb(rp, buf, MAXLINE);
		printf("%s", buf);
	} while (strcmp(buf, "\r\n"));
	printf("$end-->read_requestheaders-----------------------------\n");
	return ;
}

int parse_uri (char *uri, char *filename, char *cgiargs)
{
	char *ptr;

	if (!strstr(uri, "cgi-bin")) {	/* Static content */
		strcpy(cgiargs, "");
		strcpy(filename, "../docs");
		strcat(filename, uri);
		if (uri[strlen(uri)-1] == '/') {
			strcat(filename, "index.html");
		}
		return 1;
	} else {
		ptr = index(uri, '?');
		if (ptr) {
			strcpy(cgiargs, ptr + 1);
			*ptr = '\0';
		} else  {
			strcpy(cgiargs, "");
		}
		strcpy(filename, "../docs");
		strcat(filename, uri);
		return 0;
	}
}

void serve_static (int fd, char *filename, int filesize)
{
	int srcfd;
	char *srcp, filetype[MAXLINE], buf[MAXLINE];

	/* Send response headers to client  */
	get_filetype(filename, filetype);
	sprintf(buf, "HTTP/1.0 200 OK\r\n");
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "Server: Tyger Web Server\r\n");
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "Content-length: %d\r\n", filesize);
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "Content-type: %s; charset=uft-8\r\n\r\n", filetype);
	Rio_writen(fd, buf, strlen(buf));

	/* Send reponse body to client */
	srcfd = Open(filename, O_RDONLY, 0);
	srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
	Close(srcfd);
	Rio_writen(fd, srcp, filesize);
	Munmap(srcp, filesize);
}

void get_filetype (char *filename, char *filetype)
{
	if (strstr(filename, ".html"))
		strcpy(filetype, "text/html");
	else if (strstr(filename, ".gif"))
		strcpy(filetype, "image/gif");
	else if (strstr(filename, ".png"))
		strcpy(filetype, "image/png");
	else if (strstr(filename, ".jpg"))
		strcpy(filetype, "image/jpeg");
	else 
		strcpy(filetype, "text/plain");
}

void serve_dynamic (int fd, char *filename, char *cgiargs)
{
	char buf[MAXLINE], *emptylist[] = {NULL};
	
	sprintf(buf, "HTTP/1.0 200 OK\r\n");
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "Server: Tyger Web Server\r\n");
	Rio_writen(fd, buf, strlen(buf));
	
	if (Fork() == 0) {
		setenv("QUERY_STRING", cgiargs, 1);
		Dup2(fd, STDOUT_FILENO);
		Execve(filename, emptylist, environ);
	}
//	Wait(NULL);
}

void clienterror (int fd, char *cause, char *errnum, char *shortmsg,
					char *longmsg)
{
	char buf[MAXLINE];
	
	/* Print the HTTP response headers */
	sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "Content-type: text/html\r\n\r\n");
	Rio_writen(fd, buf, strlen(buf));

	/* Print the HTTP response body */
	sprintf(buf, "<html><title>Tyger Error</title>");
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "<body bgcolor=""ffffff"">\r\n");
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "%s: %s\r\n", errnum, shortmsg);
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "<p>%s: %s\r\n", longmsg, cause);
	Rio_writen(fd, buf, strlen(buf));
	sprintf(buf, "<hr<em>The Tyger Web Server</em>\r\n");
	Rio_writen(fd, buf, strlen(buf));
}
